package analizadorLexico.estados;

import java.util.Vector;
import tablaSimbolos.TablaSimbolos;
import analizadorLexico.tokens.Token;
import analizadorLexico.tokens.TokenError;

public class Contexto {
	
	/*lista de tokens*/
	private static Vector<Token> listaTokens=new Vector<Token>();
	
	/*lista de errores*/
	private static Vector<TokenError> listaErrores=new Vector<TokenError>();
	
	/*buffer que contiene todo el fichero leido*/
	private static StringBuffer buffer=new StringBuffer();
	
	/*buffer de lo leido para meter en el lexema del token*/
	private static StringBuffer lexema=new StringBuffer();
	
	/*posicion en el buffer*/
	private static int posicionBuffer=0;
	
	private static int posicionLinea=1;
	
	/*numero de linea*/
	private static Integer numLinea=new Integer(1);
	
	/*tabla de simbolos*/
	private static TablaSimbolos tablaSimbolos=TablaSimbolos.creaTablaSimbolos();
	
	/*estado Actual*/
	
	private static Estado estadoActual=EstadoInicial.getInstance();
	
	
	private static Contexto contexto = null;
	private Contexto() {}
 
    private synchronized static void crearInstancia() {
        if (contexto == null) contexto = new Contexto();
    }
    
    /*constructor aplicando el patron singleton*/
    public static Contexto getContexto() {
        if (contexto == null) crearInstancia();
        return contexto;
    }
    
    /*metodo que resetea el analizador*/
    public static void reset(){
    	
    	listaTokens = new Vector<Token>();
    	listaErrores = new Vector<TokenError>();
    	
    	
    	buffer = new StringBuffer();
    	
    	posicionBuffer = 0;
    	
    	lexema = new StringBuffer();
    	
    	numLinea = 1;
    	tablaSimbolos = TablaSimbolos.creaTablaSimbolos();
    	
    	estadoActual=null;
	}
    
    public static void borrarBufferLinea(){
    	buffer = new StringBuffer();
	}
    
    /*devuelve el buffer de la linea*/
    public static StringBuffer getBuffer(){
    	return buffer; 
	}
    
    /*para insertar caracteres al final del buffer*/
    public static void appendToBuffer(String s){
    	buffer.append(s);
    }
    
    /*devuelve la lista de tokens leidos*/
    public static Vector<Token> getTokens() {
		return listaTokens;
	}
    
    /*devuelve la lista de errores leidos*/
    public static Vector<TokenError> getListaErrores() {
		return listaErrores;
	}
    
    /*a�ade un token a la lista de tokens*/
    public static void addToken(Token token) {
		listaTokens.add(token);
	}
    
    /*a�ade un error a la lista de errores*/
    public static void addError(TokenError token) {
		listaErrores.add(token);
	}
    
    /*devuelve el siguiente caracter de la linea que se esta procesando y actualiza la posicion
     * por la que se esta leyendo*/
    public static char getSiguienteCaracterYAvanzar() {
    	
    	if(Contexto.esEndOfFile())
		{
		 char c=buffer.charAt(posicionBuffer-1);
		 return c;
		}
    	else
    	{
	    	char c = buffer.charAt(posicionBuffer);
			if (posicionBuffer < buffer.length())
			{
				posicionBuffer++;
				posicionLinea++;
			}
			return c;
    	}
	}
    
    /*devuelve el caracter de la posicion actual en la que se esta leyendo*/
    public static char getCaracterPosicionActual() {
		return buffer.charAt(posicionBuffer);
	}
    
    /*metodo que devuelve la linea actual por la que se va leyendo del fichero*/
    public static Integer getLineaActual() {
		return numLinea;
	}
    
    /*metodo que devuelde el lexema leido del buffer de la linea*/
    public static StringBuffer getLexema() {
		return lexema;
	}
    
    /*reseteamos el lexema leido*/
    public static void resetearLexema() {
		lexema = new StringBuffer();
	}
    
    /*modificamos el estado actual del automata*/
    public static void setEstadoActual(Estado estado) {
		estadoActual = estado;
	}
    
    /*a�ade al final del lexema el caracter de entrada*/
    public static void appendAlLexema(char caracter) {
		lexema.append(caracter);
	}

    /*aumenta en 1 el numero de linea por el que se esta procesando*/
	public static void aumentaLinea() {
		numLinea++;
	}
	
	public static void moverACaracterAnteriorBuffer() {
		if (posicionBuffer > 0) posicionBuffer--;
	}
	
	public static TablaSimbolos getTablaSimbolos() {
		return tablaSimbolos;
	}
	
	public static Estado getCEstadoActual() {
		return estadoActual;
	}
    
	public static void iniciarAutomata() {
		while(estadoActual!=null) 
			estadoActual.irASiguienteEstado();
	}
    
	public static boolean esEndOfFile() {
		return buffer.length() == posicionBuffer;
	}
	
	public static boolean esLetraMinuscula(char c)
	{
		if(c=='a'||
		   c=='b'||
		   c=='c'||
		   c=='d'||
		   c=='e'||
		   c=='f'||
		   c=='g'||
		   c=='h'||
		   c=='i'||
		   c=='j'||
		   c=='k'||
		   c=='l'||
		   c=='m'||
		   c=='n'||
		   c=='�'||
		   c=='o'||
		   c=='p'||
		   c=='q'||
		   c=='r'||
		   c=='s'||
		   c=='t'||
		   c=='u'||
		   c=='v'||
		   c=='w'||
		   c=='x'||
		   c=='y'||
		   c=='z')
			return true;
						   
		return false;
	}
	
	public static boolean esLetraMayuscula(char c)
	{
		if(c=='A'||
		   c=='B'||
		   c=='C'||
		   c=='D'||
		   c=='E'||
		   c=='F'||
		   c=='G'||
		   c=='H'||
		   c=='I'||
		   c=='J'||
		   c=='K'||
		   c=='L'||
		   c=='M'||
		   c=='N'||
		   c=='�'||
		   c=='O'||
		   c=='P'||
		   c=='Q'||
		   c=='R'||
		   c=='S'||
		   c=='T'||
		   c=='U'||
		   c=='V'||
		   c=='W'||
		   c=='X'||
		   c=='Y'||
		   c=='Z')
		return true;
								   
		return false;
	}
	
	public static boolean esDigito(char c)
	{
		if(c=='0'||c=='1'||c=='2'||c=='3'||c=='4'||c=='5'||c=='6'||c=='7'||c=='8'||c=='9')
		return true;
		
		return false;
	}
	
	public static boolean esLetra(char c)
	{
		return Contexto.esLetraMayuscula(c)||Contexto.esLetraMinuscula(c);
	}
	
	public static boolean esAlfaNumerico(char c)
	{
		return Contexto.esLetra(c)||Contexto.esDigito(c);
	}
	
    public static void generarErrorYReiniciar(String mensajeEncontrado,String mensajeEsperado){
		//error
		Contexto.addError(new TokenError(new StringBuffer("ERROR en linea:" + Contexto.getLineaActual()
							+"columna:"+Contexto.getPosicionLinea()+" esperaba "+ mensajeEsperado +" pero se encontro "
							+ Contexto.getLexema()+ mensajeEncontrado + "'"),Contexto.getLineaActual(),Contexto.getPosicionLinea()-Contexto.getLexema().length()));
		if(Contexto.esEndOfFile())
		{
			Contexto.setEstadoActual(EstadoFinal.getInstance());
		}
		else
		{
			Contexto.resetearLexema();
			Contexto.setEstadoActual(EstadoInicial.getInstance());
		}
		
	}
    
    public static int getPosicionLinea()
    {
    	return posicionLinea;
    }
    
    public static void resetPosicionLinea()
    {
    	posicionLinea=1;
    }
    
    public static void retrocederPunteroHastaParentesisAbierto()
    {
    	while(Contexto.getCaracterPosicionActual()!='(')
    	{
    		Contexto.posicionBuffer--;
    		Contexto.posicionLinea--;
    	}
    	
    	Contexto.posicionBuffer=Contexto.posicionBuffer+2;
    	Contexto.posicionLinea=Contexto.posicionLinea+2;
    }
    
    public static Token dameUltimoToken()
    {
    	return listaTokens.lastElement();
    }
}
